import 'dart:io';

import 'package:dio/dio.dart';
import 'package:my_shop/service/api_error.dart';
import 'package:my_shop/service/api_response.dart';
import 'package:my_shop/service/api_urls.dart';
import 'package:my_shop/service/interceptors/log_interceptor.dart';
import 'package:my_shop/service/interceptors/token_interceptor.dart';
import 'package:my_shop/util/loading_util.dart';
import 'package:my_shop/util/logs.dart';
import 'package:my_shop/util/toast.dart';

/// HTTP请求方法枚举
enum HttpMethod {
  get,
  post,
  put,
  delete,
  patch,
}

/// 错误处理回调函数类型
typedef ErrorHandler = void Function(int code, String message, String path);

/// HTTP客户端
class HttpClientService {
  static final HttpClientService instance = HttpClientService._internal();
  late final Dio _dio;
  bool _isInitialized = false;
  factory HttpClientService() => instance;

  HttpClientService._internal();

  void init(){
    if (_isInitialized){
      printLog('HttpClientService already init ...');
      return;
    }
    printLog('HttpClientService init start...');
    _dio = Dio();
    _initDio();
    _setupInterceptors();
    _isInitialized = true;
    printLog('HttpClientService init successful');
  }

  /// 初始化Dio配置
  void _initDio() {
    _dio.options.baseUrl = HttpApi.baseUrl;
    _dio.options.connectTimeout = const Duration(seconds: 30);
    _dio.options.receiveTimeout = const Duration(seconds: 30);
    _dio.options.headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'tenant-id': '1',
    };
  }

  /// 设置拦截器
  void _setupInterceptors() {
    _dio.interceptors.add(TokenInterceptor());
    _dio.interceptors.add(HttpLogInterceptor());
    _dio.interceptors.add(InterceptorsWrapper(
      onError: (error, handler) {
        // 确保在错误时关闭加载弹窗
        _hideLoading();
        return handler.next(error);
      },
    ));
  }

  /// 显示加载弹窗
  void _showLoading() {
    Future.delayed(Duration.zero, () {
      LoadingUtil.showLoading();
    });
  }

  /// 隐藏加载弹窗
  void _hideLoading() {
    Future.delayed(Duration.zero, () {
      LoadingUtil.hideLoading();
    });
  }

  /// 处理API响应
  Future<T> _handleResponse<T,R>(Response response, String path, ErrorHandler? errorHandler) async {
    final jsonData = response.data;
    ApiResponse<T> resp;

    // 根据泛型类型选择合适的响应类
    if (T.toString().startsWith('List<')) {
      resp = ApiListResponse<R>.fromJson(jsonData) as ApiResponse<T>;
    } else if (T.toString().startsWith('PageData<')) {
      resp = ApiPageResponse<R>.fromJson(jsonData) as ApiResponse<T>;
    } else {
      resp = ApiResponse<T>.fromJson(jsonData);
    }

    if (resp.isSuccess) {
      if (resp.data == null) {
        Toast.show(resp.msg);
        return true as T;
      }
      return resp.data!;
    } else {
      if (errorHandler != null) {
        errorHandler(resp.code, resp.msg, path);
      } else {
        ApiError.handleErr(
          resp.code,
          resp.msg,
          path,
        );
      }
      throw ApiException(
        code: resp.code,
        message: resp.msg,
      );
    }
  }

  /// 处理错误
  void _handleError(dynamic error, String path, {bool showErrorToast = true, ErrorHandler? errorHandler}) {
    if (error is Error) {
      printError('$error\n${error.stackTrace}');
    }

    if (error is ApiException) {
      if (errorHandler != null) {
        errorHandler(error.code, error.message, path);
      } else if (showErrorToast) {
        Toast.show(error.message);
      }
      throw error;
    } else {
      final errorMessage = '接口：$path  信息：${error.toString()}';
      if (errorHandler != null) {
        errorHandler(500, errorMessage, path);
      } else if (showErrorToast) {
        Toast.show(errorMessage);
      }
      throw ApiException(
        code: 500,
        message: errorMessage,
      );
    }
  }

  ///
  /// 发送请求
  /// 普通类型的请求  T ===>  SomeModel              R  ===>SomeModel
  /// 分页类型的请求  T ===>  PageModel<SomeModel>   R  ===>SomeModel
  /// 单纯列表的请求  T ===>  List<SomeModel>        R  ===>SomeModel
  ///
  Future<T> request<T,R>({
    required String path,
    required HttpMethod method,
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
    bool showLoading = true,
    bool showErrorToast = true,
    ErrorHandler? errorHandler,
  }) async {
    try {
      options ??= Options();
      options.headers ??= {};

      if (showLoading) {
        _showLoading();
      }

      final response = await _dio.request(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options..method = method.name.toUpperCase(),
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );

      if (showLoading) {
        _hideLoading();
      }

      return await _handleResponse<T,R>(response, path,errorHandler);
    } catch (error) {
      if (showLoading) {
        _hideLoading();
      }
      _handleError(error, path, showErrorToast: showErrorToast, errorHandler: errorHandler);
      rethrow;
    }
  }

  /// GET请求
  Future<T> get<T,R>({
    required String path,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
    bool showLoading = true,
    bool showErrorToast = true,
    ErrorHandler? errorHandler,
  }) {
    return request<T,R>(
      path: path,
      method: HttpMethod.get,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onReceiveProgress: onReceiveProgress,
      showLoading: showLoading,
      showErrorToast: showErrorToast,
      errorHandler: errorHandler,
    );
  }

  /// POST请求
  Future<T?> post<T,R>({
    required String path,
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
    bool showLoading = true,
    bool showErrorToast = true,
    ErrorHandler? errorHandler,
  }) {
    return request<T,R>(
      path: path,
      method: HttpMethod.post,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
      showLoading: showLoading,
      showErrorToast: showErrorToast,
      errorHandler: errorHandler,
    );
  }

  /// PUT请求
  Future<T?> put<T,R>({
    required String path,
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
    bool showLoading = true,
    bool showErrorToast = true,
    ErrorHandler? errorHandler,
  }) {
    return request<T,R>(
      path: path,
      method: HttpMethod.put,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
      showLoading: showLoading,
      showErrorToast: showErrorToast,
      errorHandler: errorHandler,
    );
  }

  /// DELETE请求
  Future<T?> delete<T,R>({
    required String path,
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    bool showLoading = true,
    bool showErrorToast = true,
    ErrorHandler? errorHandler,
  }) {
    return request<T,R>(
      path: path,
      method: HttpMethod.delete,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      showLoading: showLoading,
      showErrorToast: showErrorToast,
      errorHandler: errorHandler,
    );
  }

  /// 下载文件
  Future<File> download({
    required String url,
    required String savePath,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
    bool showLoading = true,
    bool showErrorToast = true,
  }) async {
    try {
      if (showLoading) {
        _showLoading();
      }

      final response = await _dio.download(
        url,
        savePath,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onReceiveProgress: onReceiveProgress,
      );

      if (showLoading) {
        _hideLoading();
      }

      if (response.statusCode == 200) {
        return File(savePath);
      } else {
        throw ApiException(
          code: response.statusCode ?? 500,
          message: 'Download failed with status code: ${response.statusCode}',
        );
      }
    } catch (error) {
      if (showLoading) {
        _hideLoading();
      }
      _handleError(error, url, showErrorToast: showErrorToast);
      rethrow;
    }
  }
}

/// API异常类
class ApiException implements Exception {
  final int code;
  final String message;

  ApiException({required this.code, required this.message});

  @override
  String toString() => 'ApiException: [$code] $message';
}
